package br.com.equus.entidade;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

import org.hibernate.envers.Audited;

import br.com.arquitetura.entidade.Entidade;
import br.com.arquitetura.excecao.ExcecaoUtil;
import br.com.equus.util.Constantes;

@Entity
@Table(name = "EQ_ANIMAL", catalog = "EQUUS")
@Audited
public class Animal extends Entidade<Integer> implements java.io.Serializable {

	private static final long serialVersionUID = 8949647850411745038L;

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "ID_ANIMAL", unique = true, nullable = false)
	private Integer id;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "ID_PELAGEM", referencedColumnName = "ID_PELAGEM")
	private Pelagem pelagem;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "ID_TP_ANIMAL", referencedColumnName = "ID_TP_ANIMAL")
	private TipoAnimal tipoAnimal;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "ID_RACA", referencedColumnName = "ID_RACA")
	private Raca raca;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "ID_GRAU_SANGUE", referencedColumnName = "ID_GRAU_SANGUE")
	private GrauSangue grauSangue;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "ID_TP_COBERTURA", referencedColumnName = "ID_TP_COBERTURA")
	private TipoCobertura tipoCobertura;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "ID_ANIMAL_PAI", referencedColumnName = "ID_ANIMAL")
	private Animal pai;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "ID_ANIMAL_MAE", referencedColumnName = "ID_ANIMAL")
	private Animal mae;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "ID_FUNCAO_ANIMAL", referencedColumnName = "ID_FUNCAO_ANIMAL", nullable = false)
	private FuncaoAnimal funcaoAnimal;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "ID_PROPRIETARIO", referencedColumnName = "ID_PROPRIETARIO")
	private Proprietario proprietario;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "ID_PROP_CRIADOR", referencedColumnName = "ID_PROPRIETARIO")
	private Proprietario proprietarioCriador;

	@Column(name = "DSC_OBSERVACAO", columnDefinition = "text")
	private String observacao;

	@Column(name = "NOM_ANIMAL", nullable = false, length = 255)
	private String nome;

	@Column(name = "NUM_IDADE", nullable = false)
	private Integer idade;

	@Column(name = "TP_SEXO", nullable = false, length = 1)
	private Character sexo;
	@Column(name = "ID_SITUACAO", nullable = false)
	private Integer situacao;

	@Column(name = "QTD_PARTO")
	private Integer qtdParto;

	@Column(name = "COD_IDENTIFICACAO", length = 255)
	private String codigo;

	@Temporal(TemporalType.TIMESTAMP)
	@Column(name = "DT_ENTRADA", nullable = false)
	private Date dtEntrada;

	@Temporal(TemporalType.TIMESTAMP)
	@Column(name = "DT_SAIDA")
	private Date dtSaida;

	@Column(name = "QTD_PARTO_N")
	private Integer qtdAborto;

	@OneToMany(mappedBy = "animal", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
	private Set<ImagemAnimal> imagens = new HashSet<ImagemAnimal>();

	@OneToMany(mappedBy = "animal", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
	private Set<MedicaoAnimal> medicoes = new HashSet<MedicaoAnimal>();

	@OneToMany(mappedBy = "animal", fetch = FetchType.LAZY)
	private Set<ControleDoador> doadoras = new HashSet<ControleDoador>();

	@Transient
	private List<MedicaoAnimal> medicoesToArray = new ArrayList<MedicaoAnimal>();

	@OneToMany(mappedBy = "animal", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
	private Set<AvaliacaoAnimal> avaliacoes = new HashSet<AvaliacaoAnimal>();

	@OneToMany(mappedBy = "animal", fetch = FetchType.LAZY)
	private Set<MovimentacaoAnimal> movimentacoes = new HashSet<MovimentacaoAnimal>();

	@Transient
	private List<AvaliacaoAnimal> avaliacoesToArray = new ArrayList<AvaliacaoAnimal>();

	@Transient
	private String sexoFormat;

	@Transient
	private List<String> listaUrls = new ArrayList<String>();

	@Transient
	private String urlImagemAleatoria;

	@Transient
	private Integer qtdEmbriaoEfetivado = 0;

	@Transient
	private Integer qtdEmbriaoNaoEfetivado = 0;

	@Transient
	private MovimentacaoAnimal movimentacaoAnimalAtual;

	public Animal() {
	}

	public Animal(Integer id) {
		this.id = id;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public Pelagem getPelagem() {
		return pelagem;
	}

	public void setPelagem(Pelagem pelagem) {
		this.pelagem = pelagem;
	}

	public TipoAnimal getTipoAnimal() {
		return tipoAnimal;
	}

	public void setTipoAnimal(TipoAnimal tipoAnimal) {
		this.tipoAnimal = tipoAnimal;
	}

	public Raca getRaca() {
		return raca;
	}

	public void setRaca(Raca raca) {
		this.raca = raca;
	}

	public GrauSangue getGrauSangue() {
		return grauSangue;
	}

	

	public Integer getSituacao() {
		return situacao;
	}

	public void setSituacao(Integer situacao) {
		this.situacao = situacao;
	}

	public void setGrauSangue(GrauSangue grauSangue) {
		this.grauSangue = grauSangue;
	}

	public TipoCobertura getTipoCobertura() {
		return tipoCobertura;
	}

	public void setTipoCobertura(TipoCobertura tipoCobertura) {
		this.tipoCobertura = tipoCobertura;
	}

	public Animal getPai() {
		return pai;
	}

	public void setPai(Animal pai) {
		this.pai = pai;
	}

	public Animal getMae() {
		return mae;
	}

	public void setMae(Animal mae) {
		this.mae = mae;
	}

	public Proprietario getProprietario() {
		return proprietario;
	}

	public void setProprietario(Proprietario proprietario) {
		this.proprietario = proprietario;
	}

	public String getObservacao() {
		return observacao;
	}

	public void setObservacao(String observacao) {
		this.observacao = observacao;
	}

	public String getNome() {
		return nome;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}

	public Integer getIdade() {
		return idade;
	}

	public void setIdade(Integer idade) {
		this.idade = idade;
	}

	public Date getDtEntrada() {
		return dtEntrada;
	}

	public void setDtEntrada(Date dtEntrada) {
		this.dtEntrada = dtEntrada;
	}

	public Date getDtSaida() {
		return dtSaida;
	}

	public void setDtSaida(Date dtSaida) {
		this.dtSaida = dtSaida;
	}

	public Character getSexo() {
		return sexo;
	}

	public void setSexo(Character sexo) {
		this.sexo = sexo;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((dtEntrada == null) ? 0 : dtEntrada.hashCode());
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		result = prime * result + ((nome == null) ? 0 : nome.hashCode());
		result = prime * result + ((sexo == null) ? 0 : sexo.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Animal other = (Animal) obj;
		if (dtEntrada == null) {
			if (other.dtEntrada != null)
				return false;
		} else if (!dtEntrada.equals(other.dtEntrada))
			return false;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		if (nome == null) {
			if (other.nome != null)
				return false;
		} else if (!nome.equals(other.nome))
			return false;
		if (sexo == null) {
			if (other.sexo != null)
				return false;
		} else if (!sexo.equals(other.sexo))
			return false;
		return true;
	}

	public Set<ImagemAnimal> getImagens() {
		return imagens;
	}

	public void setImagens(Set<ImagemAnimal> imagens) {
		this.imagens = imagens;
	}

	public static long getSerialversionuid() {
		return serialVersionUID;
	}

	public FuncaoAnimal getFuncaoAnimal() {
		return funcaoAnimal;
	}

	public void setFuncaoAnimal(FuncaoAnimal funcaoAnimal) {
		this.funcaoAnimal = funcaoAnimal;
	}

	public Proprietario getProprietarioCriador() {
		return proprietarioCriador;
	}

	public void setProprietarioCriador(Proprietario proprietarioCriador) {
		this.proprietarioCriador = proprietarioCriador;
	}

	public Set<MedicaoAnimal> getMedicoes() {
		return medicoes;
	}

	public void setMedicoes(Set<MedicaoAnimal> medicoes) {
		this.medicoes = medicoes;
	}

	public List<MedicaoAnimal> getMedicoesToArray() {
		if (medicoes != null) {
			medicoesToArray = new ArrayList<MedicaoAnimal>(medicoes);
		}
		return medicoesToArray;
	}

	public void setMedicoesToArray(List<MedicaoAnimal> medicoesToArray) {
		this.medicoesToArray = medicoesToArray;
	}

	public Set<AvaliacaoAnimal> getAvaliacoes() {
		return avaliacoes;
	}

	public void setAvaliacoes(Set<AvaliacaoAnimal> avaliacoes) {
		this.avaliacoes = avaliacoes;
	}

	public List<AvaliacaoAnimal> getAvaliacoesToArray() {
		if (avaliacoes != null) {
			avaliacoesToArray = new ArrayList<AvaliacaoAnimal>(avaliacoes);
		}
		return avaliacoesToArray;
	}

	public void setAvaliacoesToArray(List<AvaliacaoAnimal> avaliacoesToArray) {
		this.avaliacoesToArray = avaliacoesToArray;
	}

	public String getSexoFormat() {
		if (sexo != null && sexo.toString().equalsIgnoreCase("m")) {
			return "Macho";
		} else if (sexo != null && sexo.toString().equalsIgnoreCase("f")) {
			return "Fêmea";
		}
		return "";
	}

	public void setSexoFormat(String sexoFormat) {
		this.sexoFormat = sexoFormat;
	}

	public List<String> getListaUrls() {

		try {
			// Verifica se existem imagens
			listaUrls = new ArrayList<String>();
			if (imagens != null && !imagens.isEmpty()) {
				for (ImagemAnimal img : imagens) {
					String url = Constantes.PATH_IMG + img.getNomeImagem();

					// salva no diretorio senao existir
					File file = new File(url);
					if (!file.exists()) {
						OutputStream out = new FileOutputStream(file);
						Integer len = new Long(img.getImagem().length()).intValue();
						byte[] contents = img.getImagem().getBytes(1L, len);
						out.write(contents);
						out.flush();
						out.close();
					}
					if (!listaUrls.contains(url)) {
						listaUrls.add(url);
					}
				}
			}

		} catch (Exception e) {
			ExcecaoUtil.tratarExcecao(e);
		}
		return listaUrls;
	}

	public void setListaUrls(List<String> listaUrls) {
		this.listaUrls = listaUrls;
	}

	public Integer getQtdParto() {
		return qtdParto;
	}

	public void setQtdParto(Integer qtdParto) {
		this.qtdParto = qtdParto;
	}

	public String getCodigo() {
		return codigo;
	}

	public void setCodigo(String codigo) {
		this.codigo = codigo;
	}

	public String getUrlImagemAleatoria() {
		try {
			if (imagens != null && !imagens.isEmpty()) {
				for (ImagemAnimal img : imagens) {
					String url = Constantes.PATH_IMG + img.getNomeImagem();

					// salva no diretorio senao existir
					File file = new File(url);
					if (!file.exists()) {
						OutputStream out = new FileOutputStream(file);
						Integer len = new Long(img.getImagem().length()).intValue();
						byte[] contents = img.getImagem().getBytes(1L, len);
						out.write(contents);
						out.flush();
						out.close();
					}
					urlImagemAleatoria = url;
					break;
				}
			}

		} catch (Exception e) {
			ExcecaoUtil.tratarExcecao(e);
		}
		return urlImagemAleatoria;
	}

	public void setUrlImagemAleatoria(String urlImagemAleatoria) {
		this.urlImagemAleatoria = urlImagemAleatoria;
	}

	public Integer getQtdEmbriaoEfetivado() {
		qtdEmbriaoEfetivado = 0;
		if (doadoras != null && !doadoras.isEmpty()) {
			for (ControleDoador doadora : doadoras) {
				if (doadora.getFlgEmbriaoEfetivado() != null && doadora.getFlgEmbriaoEfetivado()) {
					if (doadora.getQtdEmbriaoEfetivado() != null) {
						qtdEmbriaoEfetivado = doadora.getQtdEmbriaoEfetivado() + qtdEmbriaoEfetivado;
					}
				}
			}
		}
		return qtdEmbriaoEfetivado;
	}

	public void setQtdEmbriaoEfetivado(Integer qtdEmbriaoEfetivado) {
		this.qtdEmbriaoEfetivado = qtdEmbriaoEfetivado;
	}

	public Integer getQtdEmbriaoNaoEfetivado() {
		qtdEmbriaoNaoEfetivado = 0;
		if (doadoras != null && !doadoras.isEmpty()) {
			for (ControleDoador doadora : doadoras) {
				if (doadora.getFlgEmbriaoEfetivado() != null && !doadora.getFlgEmbriaoEfetivado()) {
					if (doadora.getQtdEmbriaoNaoEfetivado() != null) {
						qtdEmbriaoNaoEfetivado = doadora.getQtdEmbriaoNaoEfetivado() + qtdEmbriaoNaoEfetivado;
					}
				}
			}
		}
		return qtdEmbriaoNaoEfetivado;
	}

	public void setQtdEmbriaoNaoEfetivado(Integer qtdEmbriaoNaoEfetivado) {
		this.qtdEmbriaoNaoEfetivado = qtdEmbriaoNaoEfetivado;
	}

	public Set<ControleDoador> getDoadoras() {
		return doadoras;
	}

	public void setDoadoras(Set<ControleDoador> doadoras) {
		this.doadoras = doadoras;
	}

	public Integer getQtdAborto() {
		return qtdAborto;
	}

	public void setQtdAborto(Integer qtdAborto) {
		this.qtdAborto = qtdAborto;
	}

	public Set<MovimentacaoAnimal> getMovimentacoes() {
		return movimentacoes;
	}

	public void setMovimentacoes(Set<MovimentacaoAnimal> movimentacoes) {
		this.movimentacoes = movimentacoes;
	}

	public MovimentacaoAnimal getMovimentacaoAnimalAtual() {
		MovimentacaoAnimal maior = new MovimentacaoAnimal();
		int cont = 0;
		if (movimentacoes != null && !movimentacoes.isEmpty()) {
			for (MovimentacaoAnimal mov : movimentacoes) {
				if (cont == 0) {
					maior = mov;
					cont++;
				}
				if (mov.getDtAlteracao().after(maior.getDtAlteracao())) {
					maior = mov;
				}
			}
		}
		
		return maior;
	}

	public void setMovimentacaoAnimalAtual(MovimentacaoAnimal movimentacaoAnimalAtual) {
		this.movimentacaoAnimalAtual = movimentacaoAnimalAtual;
	}

}
